#pragma once

#include <memory>
#include <vector>
#include <functional>
#include <unordered_map>

using TaskFunc = std::function<void()>;
class TimerTask;
class EventLoop;
class Channel;
class TimerWheel
{
private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;

    int _tick;                                // 当前表盘的秒针，走到哪里就释放到哪里
    int _capacity;                            // 表盘最大数量，其实就是最大延迟时间
    std::vector<std::vector<PtrTask>> _wheel; // 外层 vector 表示时间轮的每一个“刻度”），内层 vector 表示该刻度上可能有多个定时任务。
    std::unordered_map<uint64_t, WeakTask> _timers;
    EventLoop *_loop;
    int _timerfd; // 定时器描述符  --- 可读事件回调就是读取定时器，执行定时任务
    std::unique_ptr<Channel> _timer_channel;

public:
    TimerWheel(EventLoop *loop);

public:
    // 1. 移除定时定时任务
    void RemoveTimer(uint64_t id);

    // 2. 创建一个定时器文件描述符
    static int CreateTimerFd();

    // 3. 读取定时器文件描述符
    int ReadTimeFd();

    // 4. 执行时间轮里面的定时任务
    void RunTimerTask();

    // 5. 根据超时时间，执行定时任务
    void Ontime();

    // 6. 添加定时任务
    void TimerAddInLoop(uint64_t id, uint32_t delay, const TaskFunc &cb);

    // 7. 刷新/延迟定时任务
    void TimerRefreshInLoop(uint64_t id);

    // 8.
    void TimerCancelInLoop(uint64_t id);

    //定时器中有个_timers成员，定时器信息的操作有可能在多线程中进行(如主线程想添加给所有的连接添加一个定时任务)，因此需要考虑线程安全问题
    //如果不想加锁，那就把对应定期的所有操作，都放到一个线程中进行
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb);
    void TimerRefresh(uint64_t id);
    void TimerCancel(uint64_t id);
    bool HasTimer(uint64_t id);
};